package com.mys.maggie.redis.api.spring.impl;

import com.mys.maggie.redis.api.bean.RedisSort;
import com.mys.maggie.redis.api.spring.MagRedisService;
import org.springframework.data.redis.core.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * desc: redis接口方法 服务实现
 * date:2020/5/21 14:44
 */
public class MagRedisServiceImpl implements MagRedisService {
    private RedisTemplate<String, Object> redisTemplate;

    private String clusterName;

    public MagRedisServiceImpl(RedisTemplate<String, Object> redisTemplate, String clusterName) {
        this.redisTemplate = redisTemplate;
        this.clusterName = clusterName;
    }

    public RedisTemplate<String, Object> getRedisTemplateJackson() {
        return redisTemplate;
    }

    public void setRedisTemplateJackson(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void set(String key, Object value) {
        this.redisTemplate.opsForValue().set(key, value);
    }

    /**
     * set命令
     * @param key  key
     * @param value value
     * @param seconds 过期时间
     */
    @Override
    public <T> Boolean set(String key, T value, long seconds) {
        if (seconds > 0L) {
            this.redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
        }
        return true;
    }

    /**
     * key剩余的过期时间 单位：秒
     * @param key key
     * @return  key有效的秒数
     */
    @Override
    public Long getExpire(String key) {
        return this.redisTemplate.getExpire(key);
    }

    /**
     * exists key是否存在
     * @return true存在，false不存在
     */
    @Override
    public Boolean hasKey(String key) {
        return this.redisTemplate.hasKey(key);
    }

    /**
     * persist 移出key的过期时间，即:将key转成永久存储
     */
    @Override
    public Boolean persistKey(String key) {
        return this.redisTemplate.persist(key);
    }

    /**
     * 泛型get
     */
    @Override
    public  <T> T get(String key) {
        Object obj = this.redisTemplate.opsForValue().get(key);
        if(obj!=null){
            return (T)obj;
        }
        return null;
    }

    /**
     * 返回 key 中字符串值的子字符串，字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
     */
    @Override
    public String get(String key, long start, long end) {
        return this.redisTemplate.opsForValue().get(key, start, end);
    }

    /**
     * 同时设置一个或多个 key-value 对。
     * @param map 键值对
     *  示例：MSET date "2012.3.30" time "11:00 a.m." weather "sunny"
     * @return 总是返回 OK 也就是 true
     */
    @Override
    public <V> Boolean multiSet(Map<String, ? extends V> map) {
        this.redisTemplate.opsForValue().multiSet(map);
        return true;
    }

    /**
     * 同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在。
     * @param m keysvalues 键值对
     * @return 当所有 key 都成功设置，返回 1 。如果所有给定 key 都设置失败(至少有一个 key 已经存在)，那么返回 0 。
     */
    @Override
    public <V> Boolean multiSetIfAbsent(Map<String, ? extends V> m) {
        return this.redisTemplate.opsForValue().multiSetIfAbsent(m);
    }

    /**
     * 返回所有(一个或多个)给定 key 的值。
     * @param keys keys
     * @return 一个包含所有给定 key 的值的列表。
     */
    @Override
    public <T> Map<String, T> multiGet(List<String> keys) {
        List<Object> values = this.redisTemplate.opsForValue().multiGet(keys);
        Map<String, T> map = new HashMap<>();
        int i = 0;
        for(int l = keys.size(); i < l; ++i) {
            Object v = values.get(i);
            if (v != null) {
                String key = (String)keys.get(i);
                map.put(key, (T)v);
            }
        }
        return map;
    }

    /**
     * 将 key 所储存的值加上增量 increment 。
     * @param key key
     * @param value 增量值
     * @return 加上 increment 之后， key 的值。
     */
    @Override
    public Long increment(String key, long value) {
        return this.redisTemplate.opsForValue().increment(key, value);
    }

    /**
     * 如果 key 已经存在并且是一个字符串， APPEND 命令将 value 追加到 key 原来的值的末尾。
     * @param key key
     * @param value value
     * @return 返回 追加 value 之后， key 中字符串的长度。
     */
    @Override
    public Integer append(String key, String value) {
        return this.redisTemplate.opsForValue().append(key, value);
    }

    /**
     * 将 key 的值设为 value ，当且仅当 key 不存在。
     * @param key key
     * @param value value
     * @return 设置成功，返回 1 。 设置失败，返回 0 。
     */
    @Override
    public <T> Boolean setIfAbsent(String key, T value) {
        return this.redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 返回 key 所储存的字符串值的长度。
     * @param key KEY
     * @return 字符串值的长度。 当 key 不存在时，返回 0 。
     */
    @Override
    public Long size(String key) {
        return this.redisTemplate.opsForValue().size(key);
    }

    /**
     * 对 key 所储存的字符串值，设置或清除指定偏移量上的位(bit)。
     * 位的设置或清除取决于 value 参数，可以是 0 也可以是 1 。
     * 当 key 不存在时，自动生成一个新的字符串值。
     * @param key key
     * @param offset 参数必须大于或等于 0 ，小于 2^32 (bit 映射被限制在 512 MB 之内)。
     * @param value boolean
     * @return 指定偏移量原来储存的位。
     */
    @Override
    public Boolean setBit(String key, long offset, boolean value) {
        return this.redisTemplate.opsForValue().setBit(key, offset, value);
    }

    /**
     *对 key 所储存的字符串值，获取指定偏移量上的位(bit)。
     * @param key key
     * @param offset 偏移量
     * @return  当 offset 比字符串值的长度大，或者 key 不存在时，返回 0
     */
    @Override
    public Boolean getBit(String key, long offset) {
        return this.redisTemplate.opsForValue().getBit(key, offset);
    }

    /**
     * 设置key的过期时间，超过时间后，将会自动删除该key。单位是秒
     * @param key key
     * @param expire 秒数
     * @return 1 如果成功设置过期时间。 0 如果key不存在或者不能设置过期时间。
     */
    @Override
    public Boolean expire(String key, long expire) {
        return this.redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    /**
     * 删除一个key
     * @param key key
     * @return 被删除 key 的数量。
     */
    @Override
    public Boolean remove(String key) {
        return this.redisTemplate.delete(key);
    }

    /**
     * 删除一个key
     * @param keys key
     * @return 被删除 key 的数量。
     */
    @Override
    public Long remove(Collection<String> keys) {
        return this.redisTemplate.delete(keys);
    }

    /**
     * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定。
     * @param key key
     * @param start 开始
     * @param end 结束
     * @return 一个列表，包含指定区间内的元素。
     */
    @Override
    public List<Object> listRange(String key, long start, long end) {
        return this.redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 对一个列表进行修剪(trim)，就是说，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除。
     * 举个例子，执行命令 LTRIM list 0 2 ，表示只保留列表 list 的前三个元素，其余元素全部删除。
     * @param key key
     * @param start 开始
     * @param end 结束
     * @return 命令执行成功时，返回 ok 。
     */
    @Override
    public <T> Boolean listTrim(String key, long start, long end) {
        this.redisTemplate.opsForList().trim(key, start, end);
        return true;
    }


    /**
     * 返回列表 key 的长度。 如果 key 不存在，则 key 被解释为一个空列表，返回 0 .
     * @param key key
     * @return 列表 key 的长度。
     */
    @Override
    public <T> Long listSize(String key) {
        return this.redisTemplate.opsForList().size(key);
    }

    /**
     * 将列表 key 下标为 index 的元素的值设置为 value 。
     * @param key key
     * @param index 索引
     * @param value 值
     * @return 操作成功返回 ok ，否则返回错误信息。
     */
    @Override
    public <T> Boolean listSet(String key, long index, T value) {
        this.redisTemplate.opsForList().set(key, index, value);
        return true;
    }

    /**
     * 根据参数 count 的值，移除列表中与参数 value 相等的元素。
     * @param key key
     * @param count count > 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。
     *              count < 0 : 从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。
     *              count = 0 : 移除表中所有与 value 相等的值。
     * @param value 值
     * @return 被移除元素的数量。
     */
    @Override
    public <T> Long listRemove(String key, long count, Object value) {
        return this.redisTemplate.opsForList().remove(key, count, value);
    }

    /**
     * 返回列表 key 中，下标为 index 的元素。
     * @param key key
     * @param index 索引
     * @return 返回列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range)，返回 nil 。
     */
    @Override
    public <T> T  listIndex(String key, long index) {
        Object object = this.redisTemplate.opsForList().index(key, index);
        if (null != object){
            return (T)object;
        }
        return null;
    }

    /**
     * 移除并返回列表 key 的头元素。
     * @param key key
     * @return 列表的头元素。当 key 不存在时，返回 nil 。
     */
    @Override
    public <T> T listLeftPop(String key) {
        Object object =  this.redisTemplate.opsForList().leftPop(key);
        if (null != object){
            return (T)object;
        }
        return null;
    }

    /**
     * 移出并获取该列表中的第一个元素。或者阻塞，直到有一个可用
     * 当给定列表内没有任何元素可供弹出的时候， 连接将被 BLPOP 命令阻塞。
     * @param timeout 超时时间
     * @param key key
     * @return 如果列表为空，返回一个 nil.否则，返回一个含有两个元素的列表，第一个元素是被弹出元素所属的 key ，第二个元素是被弹出元素的值。
     */
    @Override
    public <T> T ListLeftPop(String key, long timeout, TimeUnit unit) {
        Object object = this.redisTemplate.opsForList().leftPop(key, timeout, unit);
        if (null != object){
            return (T)object;
        }
        return null;
    }

    /**
     * 命令移出并获取列表的最后一个元素，
     * @param key key
     * @return 假如在指定时间内没有任何元素被弹出，则返回一个 nil 和等待时长。
     *          反之，返回一个含有两个元素的列表，第一个元素是被弹出元素所属的 key ，第二个元素是被弹出元素的值。
     */
    public <T> T ListRightPop(String key) {
        Object object = this.redisTemplate.opsForList().rightPop(key);
        if (null != object){
            return (T)object;
        }
        return null;
    }

    /**
     * 命令移出并获取列表的最后一个元素， 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
     * @param timeout 超时时间
     * @param key key
     * @return 假如在指定时间内没有任何元素被弹出，则返回一个 nil 和等待时长。
     *          反之，返回一个含有两个元素的列表，第一个元素是被弹出元素所属的 key ，第二个元素是被弹出元素的值。
     */
    @Override
    public <T> T ListRightPop(String key, long timeout, TimeUnit unit) {
        Object object = this.redisTemplate.opsForList().rightPop(key, timeout, unit);
        if (null != object){
            return (T)object;
        }
        return null;
    }

    /**
     *在一个原子时间内，执行以下两个动作：
     * 将列表 source 中的最后一个元素(尾元素)弹出，并返回给客户端。
     * 将 source 弹出的元素插入到列表 destination ，作为 destination 列表的的头元素。
     * @param sourceKey 原数据key
     * @param destinationKey 目标key
     * @return 被弹出的元素。
     */
    @Override
    public <T> T ListRightPopAndLeftPush(String sourceKey, String destinationKey) {
        Object object = this.redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey);
        if (null != object){
            return (T)object;
        }
        return null;
    }

    /**
     * 从列表中取出最后一个元素，并插入到另外一个列表的头部；如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
     * @param sourceKey 原
     * @param destinationKey 目标
     * @param timeout 超时时间
     * @return 假如在指定时间内没有任何元素被弹出，则返回一个 nil 和等待时长。
     * 反之，返回一个含有两个元素的列表，第一个元素是被弹出元素的值，第二个元素是等待时长。
     */
    @Override
    public <T> T ListRightPopAndLeftPush(String sourceKey, String destinationKey, long timeout, TimeUnit unit) {
        Object object = this.redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey, timeout, unit);
        if (null != object){
            return (T)object;
        }
        return null;
    }

    /**
     * 将一个或多个值 value 插入到列表 key 的表头
     * @param key key
     * @param value 多个值
     * @return 执行 LPUSH 命令后，列表的长度。
     */
    @Override
    public <T> Long ListLeftPushAll(String key, T... value) {
        return this.redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * 将值 value 插入到列表 key 的表头，当且仅当 key 存在并且是一个列表。
     * @param key key
     * @param value 值
     * @return 表的长度。
     */
    @Override
    public <T> Long ListLeftPushIfPresent(String key, T value) {
        return this.redisTemplate.opsForList().leftPushIfPresent(key, value);
    }

    /**
     * 将值 value 插入到列表 key 当中，位于值 pivot 之前或之后。
     * 当 pivot 不存在于列表 key 时，不执行任何操作。当 key 不存在时， key 被视为空列表，不执行任何操作。
     * @param key key
     * @param pivot 标识值
     * @param value 要插入的值
     * @return 如果命令执行成功，返回插入操作完成之后，列表的长度。
     * 如果没有找到 pivot ，返回 -1 。如果 key 不存在或为空列表，返回 0 。
     */
    @Override
    public <T> Long ListLeftPush(String key, T pivot, T value) {
        return this.redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * 将值 value 插入到列表 key 的表头，当且仅当 key 存在并且是一个列表。
     * @param key key
     * @param value 值
     * @return 表的长度。
     */
    @Override
    public <T> Long ListLeftPush(String key, T value) {
        return this.redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 将值 value 插入到列表 key 的表尾，当且仅当 key 存在并且是一个列表。
     * @param key key
     * @param value 值
     * @return 表的长度。
     */
    @Override
    public <T> Long ListRightPush(String key, T value) {
        return this.redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 将值 value 插入到列表 key 当中，位于值 pivot 之前或之后。
     * 当 pivot 不存在于列表 key 时，不执行任何操作。当 key 不存在时， key 被视为空列表，不执行任何操作。
     * @param key key
     * @param pivot 标识值
     * @param value 要插入的值
     * @return 如果命令执行成功，返回插入操作完成之后，列表的长度。
     * 如果没有找到 pivot ，返回 -1 。如果 key 不存在或为空列表，返回 0 。
     */
    @Override
    public <T> Long ListRightPush(String key, T pivot, T value) {
        return this.redisTemplate.opsForList().rightPush(key, pivot, value);
    }

    /**
     * 将值 value 插入到列表 key 的表尾，当且仅当 key 存在并且是一个列表。
     * @param key key
     * @param value 值
     * @return 表的长度。
     */
    @Override
    public <T> Long ListRightPushIfPresent(String key, T value) {
        return this.redisTemplate.opsForList().rightPushIfPresent(key, value);
    }

    /**
     * 将一个或多个值 value 插入到列表 key 的表尾(最右边)。 如果 key 不存在，一个空列表会被创建并执行 RPUSH 操作。
     * @param key key
     * @param value 值
     * @return 执行 RPUSH 操作后，表的长度。
     */
    @Override
    public <T> Long rightPushAll(String key, T... value) {
        return this.redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * 将哈希表 key 中的域 field 的值设为 value 。
     * 如果 key 不存在，一个新的哈希表被创建并进行 HSET 操作。如果域 field 已经存在于哈希表中，旧值将被覆盖。
     * @param key key
     * @param hashKey 域
     * @param value 值
     * @return 如果 field 是哈希表中的一个新建域，并且值设置成功，返回 1. 如果哈希表中域 field 已经存在且旧值已被新值覆盖，返回 0 。
     */
    @Override
    public <T> boolean hashPut(String key, T hashKey, T value) {
        this.redisTemplate.opsForHash().put(key, hashKey, value);
        return true;
    }

    /**
     * 同时将多个 field-value (域-值)对设置到哈希表 key 中。  此命令会覆盖哈希表中已存在的域。
     * 如果 key 不存在，一个空哈希表被创建并执行 HMSET 操作。
     * @param key key
     * @param m map
     * @return 如果命令执行成功，返回 OK 。 当 key 不是哈希表(hash)类型时，返回一个错误。
     */
    @Override
    public <T, HV> boolean hashPutAll(String key, Map<String, ? extends HV> m) {
        this.redisTemplate.opsForHash().putAll(key, m);
        return true;
    }

    /**
     *将哈希表 key 中的域 field 的值设置为 value ，当且仅当域 field 不存在。
     * 若域 field 已经存在，该操作无效。 如果 key 不存在，一个新哈希表被创建并执行 HSETNX 命令。
     * @param key key
     * @param hashKey 阈
     * @param value 值
     * @return 设置成功，返回 1 。如果给定域已经存在且没有操作被执行，返回 0 。
     */
    @Override
    public <T, HK, HV> boolean hashPutIfAbsent(String key, HK hashKey, HV value) {
        return this.redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    }

    /**
     * 删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略。
     * @param key key
     * @param hashKey 阈
     * @return 被成功移除的域的数量，不包括被忽略的域。
     */
    @Override
    public <T, HK> Long hashDelete(String key, HK... hashKey) {
        return this.redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 查看哈希表 key 中，给定域 field 是否存在。
     * @param key key
     * @param hashKey 阈
     * @return  如果哈希表含有给定域，返回 1 。如果哈希表不含有给定域，或 key 不存在，返回 0 。
     */
    @Override
    public <T, HK> boolean hashHasKey(String key, HK hashKey) {
        return this.redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * 返回哈希表 key 中给定域 field 的值。
     * @param key key
     * @param hashKey 阈
     * @return 给定域的值。
     */
    @Override
    public <T, HK> T hashGet(String key, HK hashKey) {
        Object obj = this.redisTemplate.opsForHash().get(key, hashKey);
        if (null != obj){
            return (T)obj;
        }
        return null;
    }

    /**
     * 返回哈希表 key 中，一个或多个给定域的值。如果给定的域不存在于哈希表，那么返回一个 nil 值。
     * 因为不存在的 key 被当作一个空哈希表来处理，所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。
     * @param key key
     * @param hashKeys 阈数组
     * @return 一个包含多个给定域的关联值的表，表值的排列顺序和给定域参数的请求顺序一样。
     */
    @Override
    public <T> T hashMultiGet(String key, Collection<Object> hashKeys) {
        Object obj = this.redisTemplate.opsForHash().multiGet(key, hashKeys);
        if (null != obj){
            return (T)obj;
        }
        return null;
    }

    /**
     * 为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数，相当于对给定域进行减法操作。
     * @param key key
     * @param hashKey 阈
     * @param delta 值
     * @return 执行 HINCRBY 命令之后，哈希表 key 中域 field 的值。
     */
    @Override
    public <T, HK> Long hashIncrement(String key, HK hashKey, long delta) {
        return this.redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * 为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数，相当于对给定域进行减法操作。
     * @param key key
     * @param hashKey 阈
     * @param delta 值
     * @return 执行 HINCRBY 命令之后，哈希表 key 中域 field 的值。
     */
    @Override
    public <T, HK> Double hashIncrement(String key, HK hashKey, double delta) {
        return this.redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * 返回哈希表 key 中的所有域。
     * @param key key
     * @return 一个包含哈希表中所有域的表。 当 key 不存在时，返回一个空表。
     */
    @Override
    public <T> Set<T> hashKeys(String key) {
        Object obj = this.redisTemplate.opsForHash().keys(key);
        if (obj != null){
            return (Set)obj;
        }
        return null;
    }

    /**
     * 返回哈希表 key 中域的数量。
     * @param key key
     * @return 哈希表中域的数量。 当 key 不存在时，返回 0 。
     */
    @Override
    public <T> Long hashSize(String key) {
        return this.redisTemplate.opsForHash().size(key);
    }

    /**
     * 返回哈希表 key 中所有域的值。
     * @param key key
     * @return 一个包含哈希表中所有值的表。 当 key 不存在时，返回一个空表。
     */
    @Override
    public <T> List<T> hashValues(String key) {
        Object obj = this.redisTemplate.opsForHash().values(key);
        if (obj != null){
            return (List)obj;
        }
        return null;
    }

    /**
     * 返回哈希表 key 中，所有的域和值。
     * @param key key
     * @return 以列表形式返回哈希表的域和域的值。 若 key 不存在，返回空列表。
     */
    @Override
    public <T> T hashEntries(String key) {
        Object map = this.redisTemplate.opsForHash().entries(key);
        if (map!=null){
            return (T)map;
        }
        return null;
    }

    /**
     * 用于迭代哈希键中的键值对
     * @param key key
     * @return 键值对
     */
    @Override
    public Cursor<Map.Entry<Object, Object>> hashScan(String key) {
        return this.redisTemplate.opsForHash().scan(key, ScanOptions.NONE);
    }

    /**
     * 将一个或多个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略。
     * @param key key
     * @param value 成员
     * @return 被添加到集合中的新元素的数量，不包括被忽略的元素。
     */
    @Override
    public <T> Long setAdd(String key, T... value) {
        return this.redisTemplate.opsForSet().add(key, value);
    }

    /**
     * 移除集合 key 中的一个或多个 member 元素，不存在的 member 元素会被忽略。
     * @param key key
     * @param value 成员
     * @return 被成功移除的元素的数量，不包括被忽略的元素。
     */
    @Override
    public <T> Long setRemove(String key, T... value) {
        return this.redisTemplate.opsForSet().remove(key, value );
    }

    /**
     * 移除并返回集合中的一个随机元素。
     * @param key key
     * @return 被移除的随机元素。当 key 不存在或 key 是空集时，返回 nil 。
     */
    @Override
    public <T> Object setPop(String key) {
        return this.redisTemplate.opsForSet().pop(key);
    }

    /**
     * 将 member 元素从 source 集合移动到 destination 集合。
     * @param key 原key
     * @param value 元素
     * @param destKey 目标key
     * @return 如果 member 元素被成功移除，返回 1 。
     * 如果 member 元素不是 source 集合的成员，并且没有任何操作对 destination 集合执行，那么返回 0 。
     */
    @Override
    public Boolean setMove(String key, Object value, String destKey) {
        return this.redisTemplate.opsForSet().move(key, value, destKey);
    }

    /**
     * 返回集合 key 的基数(集合中元素的数量)。
     * @param key key
     * @return 集合的基数。 当 key 不存在时，返回 0
     */
    @Override
    public <T> Long setSize(String key) {
        return this.redisTemplate.opsForSet().size(key);
    }

    /**
     * 判断 member 元素是否集合 key 的成员。
     * @param key KEY
     * @param value 成员
     * @return 如果 member 元素是集合的成员，返回 1 。如果 member 元素不是集合的成员，或 key 不存在，返回 0 。
     */
    @Override
    public Boolean setIsMember(String key, Object value) {
        return this.redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * 返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。
     * @param key key
     * @param otherKey otherKey
     * @return 交集成员的列表。
     */
    @Override
    public Set<Object> setIntersect(String key, String otherKey) {
        return this.redisTemplate.opsForSet().intersect(key, otherKey);
    }

    /**
     * 命令将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在，则将其覆盖。
     * @param key 目标集合key
     * @param otherKeys keys
     * @return 结果集中的成员数量。
     */
    @Override
    public Set<Object> setIntersectKeys(String key, List<String> otherKeys) {
        return this.redisTemplate.opsForSet().intersect(key, otherKeys);
    }

    /**
     * 将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在，则将其覆盖。
     * @param key key
     * @param otherKey otherKey
     * @param destKey destKey
     * @return 结果集中的成员数量。
     */
    @Override
    public Long setIntersectAndStore(String key, String otherKey, String destKey) {
        return this.redisTemplate.opsForSet().intersectAndStore(key, otherKey, destKey);
    }

    /**
     * 将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在，则将其覆盖。
     * @param key key
     * @param otherKeys otherKeys
     * @param destKey destKey
     * @return 结果集中的成员数量。
     */
    @Override
    public Long setIntersectAndStore(String key, List<String> otherKeys, String destKey) {
        return this.redisTemplate.opsForSet().intersectAndStore(key, otherKeys, destKey);
    }

    /**
     * 返回一个集合的全部成员，该集合是所有给定集合的并集。不存在的 key 被视为空集。
     * @param key key
     * @param otherKey otherKey
     * @return 并集成员的列表。
     */
    @Override
    public Set<Object> setUnion(String key, String otherKey) {
        return this.redisTemplate.opsForSet().union(key, otherKey);
    }

    /**
     * 返回一个集合的全部成员，该集合是所有给定集合的并集。不存在的 key 被视为空集。
     * @param key key
     * @param otherKeys otherKeys
     * @return 并集成员的列表。
     */
    @Override
    public Set<Object> setUnion(String key, List<String> otherKeys) {
        return this.redisTemplate.opsForSet().union(key, otherKeys);
    }

    /**
     * 这个命令类似于 SUNION 命令，但它将结果保存到 destination 集合，而不是简单地返回结果集。
     * @param key key
     * @param otherKey otherKey
     * @param destKey 目标key
     * @return 结果集中的元素数量。
     */
    @Override
    public Long setUnionAndStore(String key, String otherKey, String destKey) {
        return this.redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * 这个命令类似于 SUNION 命令，但它将结果保存到 destination 集合，而不是简单地返回结果集。
     * @param key key
     * @param otherKeys otherKeys
     * @param destKey 目标key
     * @return 结果集中的元素数量。
     */
    @Override
    public Long setUnionAndStore(String key, List<String> otherKeys, String destKey) {
        return this.redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey);
    }

    /**
     * 返回一个集合的全部成员，该集合是所有给定集合之间的差集。
     * @param key key
     * @param otherKeys otherKeys
     * @return 差集
     */
    @Override
    public Set<Object> setDifference(String key, List<String> otherKeys) {
        return this.redisTemplate.opsForSet().difference(key, otherKeys);
    }

    /**
     * 返回一个集合的全部成员，该集合是所有给定集合之间的差集。
     * @param key key
     * @param otherKey otherKey
     * @return 差集
     */
    @Override
    public Set<Object> setDifference(String key, String otherKey) {
        return this.redisTemplate.opsForSet().difference(key, otherKey);
    }

    /**
     * 这个命令的作用和 SDIFF 类似，但它将结果保存到 destination 集合。
     * @param key key
     * @param otherKeys otherKey
     * @param destKey 目标结果集key
     * @return 是所有给定集合的成员数量之和。
     */
    @Override
    public Long setDifferenceAndStore(String key, List<String> otherKeys, String destKey) {
        return this.redisTemplate.opsForSet().differenceAndStore(key, otherKeys, destKey);
    }

    /**
     * 这个命令的作用和 SDIFF 类似，但它将结果保存到 destination 集合。
     * @param key key
     * @param otherKey otherKey
     * @param destKey 目标结果集key
     * @return 是所有给定集合的成员数量之和。
     */
    @Override
    public Long setDifferenceAndStore(String key, String otherKey, String destKey) {
        return this.redisTemplate.opsForSet().differenceAndStore(key, otherKey, destKey);
    }

    /**
     * 返回集合 key 中的所有成员。
     * @param key key
     * @return set
     */
    @Override
    public Set<Object> setMembers(String key) {
        return this.redisTemplate.opsForSet().members(key);
    }

    /**
     * 如果命令执行时，返回集合中的一个随机元素。
     * @param key key
     * @return obj
     */
    @Override
    public Object setRandomMember(String key) {
        return this.redisTemplate.opsForSet().randomMember(key);
    }

    /**
     * 命令用于迭代集合键中的元素
     * @param key key
     * @return obj
     */
    @Override
    public Cursor<Object> setScan(String key) {
        return this.redisTemplate.opsForSet().scan(key, ScanOptions.NONE);
    }

    /**
     * 命令用于迭代集合键中的元素
     * @param key key
     * @return obj
     */
    @Override
    public Cursor<Object> setScan(String key, ScanOptions options) {
        return this.redisTemplate.opsForSet().scan(key, options);
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
     * @param key key
     * @param value 值
     * @param score 分数  可以是整数值或双精度浮点数。
     * @return 被成功添加的新成员的数量
     */
    @Override
    public <T> Boolean ZSetAdd(String key, T value, double score) {
        return this.redisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
     * @param key key
     * @param tuples 元素集合
     * @return 被成功添加的新成员的数量
     */
    @Override
    public Long ZSetAdd(String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
        return this.redisTemplate.opsForZSet().add(key, tuples);
    }

    /**
     * 移除有序集 key 中的一个或多个成员，不存在的成员将被忽略。
     * @param key key
     * @param values 值
     * @return 被成功移除的成员的数量
     */
    @Override
    public <T> Long ZSetRemove(String key, Object... values) {
        return this.redisTemplate.opsForZSet().remove(key, values);
    }

    /**
     *为有序集 key 的成员 member 的 score 值加上增量 increment 。
     * @param key key
     * @param value 值
     * @param delta 数
     * @return member 成员的新 score 值，以字符串形式表示。
     */
    @Override
    public <T> Double ZSetIncrementScore(String key, T value, double delta) {
        return this.redisTemplate.opsForZSet().incrementScore(key, value, delta);
    }

    /**
     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
     * @param key key
     * @param value value
     * @return  如果 member 是有序集 key 的成员，返回 member 的排名。
                如果 member 不是有序集 key 的成员，返回 nil 。
     */
    @Override
    public Long ZSetRank(String key, Object value) {
        return this.redisTemplate.opsForZSet().rank(key, value);
    }

    /**
     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
     * @param key key
     * @param value value
     * @return 如果 member 是有序集 key 的成员，返回 member 的排名。
     */
    @Override
    public Long ZSetReverseRank(String key, Object value) {
        return this.redisTemplate.opsForZSet().reverseRank(key, value);
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。
     * @param key key
     * @param start 开始
     * @param end 结束
     * @return 指定区间内，带有 score 值(可选)的有序集成员的列表。
     */
    @Override
    public Set<Object> ZSetRange(String key, long start, long end) {
        return this.redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 返回有序集 key 中，指定区间内的成员，带分数、
     * @param key key
     * @param start 开始
     * @param end 结束
     * @return 返回有序集 key 中，指定区间内的成员，带分数、
     */
    @Override
    public Set<ZSetOperations.TypedTuple<Object>> ZSetRangeWithScores(String key, long start, long end) {
        return this.redisTemplate.opsForZSet().rangeWithScores(key, start, end);
    }

    /**
     * 返回有序集 key 中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
     * @param key key
     * @param min 范围--小
     * @param max 范围--大
     * @return set 集合
     */
    @Override
    public Set<Object> ZSetRangeByScore(String key, double min, double max) {
        return this.redisTemplate.opsForZSet().rangeByScore(key, min, max);
    }

    /**
     * 返回在分数之内的成员以及分数.
     * @param key key
     * @param min 范围--小
     * @param max 范围--大
     * @return set 集合
     */
    @Override
    public Set<ZSetOperations.TypedTuple<Object>> ZSetRangeByScoreWithScores(String key, double min, double max) {
        return this.redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
    }

    /**
     *返回在分数之内的成员以及分数. 带偏移量
     * @return set
     */
    @Override
    public Set<ZSetOperations.TypedTuple<Object>> ZSetRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        return this.redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, offset, count);
    }

    /**
     *返回有序集 key 中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
     * @return set
     */
    @Override
    public Set<Object> ZSetRangeByScore(String key, double min, double max, long offset, long count) {
        return this.redisTemplate.opsForZSet().rangeByScore(key, min, max, offset, count);
    }

    /**
     *返回有序集 key 中，指定区间内的成员。 其中成员的位置按 score 值递减(从大到小)来排列。
     * @return Set
     */
    @Override
    public Set<Object> ZSetReverseRange(String key, long start, long end) {
        return this.redisTemplate.opsForZSet().reverseRange(key, start, end);
    }

    /**
     *返回有序集 key 中，指定区间内的成员带分数。其中成员的位置按 score 值递减(从大到小)来排列。
     * @return Set
     */
    @Override
    public Set<ZSetOperations.TypedTuple<Object>> ZSetReverseRangeWithScores(String key, long start, long end) {
        return this.redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。
     * @return Set
     */
    @Override
    public Set<Object> ZSetReverseRangeByScore(String key, double min, double max) {
        return this.redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。带分数
     * @return Set<ZSetOperations.TypedTuple<Object>>
     */
    @Override
    public Set<ZSetOperations.TypedTuple<Object>> ZSetReverseRangeByScoreWithScores(String key, double min, double max) {
        return this.redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max);
    }

    /**
     *返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。
     * @return Set<Object>
     */
    @Override
    public Set<Object> ZSetReverseRangeByScore(String key, double min, double max, long offset, long count) {
        return this.redisTemplate.opsForZSet().reverseRangeByScore(key, min, max, offset, count);
    }

    /**
     *返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。带分数
     * @return Set<ZSetOperations.TypedTuple<Object>>
     */
    @Override
    public Set<ZSetOperations.TypedTuple<Object>> ZSetReverseRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        return this.redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max, offset, count);
    }

    /**
     * 返回有序集 key 中， score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。
     * @param key key
     * @param min 小
     * @param max 大
     * @return Long
     */
    @Override
    public Long ZSetCount(String key, double min, double max) {
        return this.redisTemplate.opsForZSet().count(key, min, max);
    }

    /**
     * 返回有序集 key 的基数。
     * @param key key
     * @return Long
     */
    @Override
    public Long ZSetSize(String key) {
        return this.redisTemplate.opsForZSet().size(key);
    }

    /**
     * 返回有序集 key 的基数。
     * @param key key
     * @return Long
     */
    @Override
    public Long ZSetzCard(String key) {
        return this.redisTemplate.opsForZSet().zCard(key);
    }

    /**
     * 返回有序集 key 中，成员 member 的 score 值。
     * @param key key
     * @param o 对象
     * @return 分数值
     */
    @Override
    public Double ZSetScore(String key, Object o) {
        return this.redisTemplate.opsForZSet().score(key, o);
    }

    /**
     * 移除有序集 key 中，指定排名(rank)区间内的所有成员。
     * 区间分别以下标参数 start 和 stop 指出，包含 start 和 stop 在内。
     * @param key key
     * @param start 开始
     * @param end 结束
     * @return 被移除成员的数量。
     */
    @Override
    public Long ZSetRemoveRange(String key, long start, long end) {
        return this.redisTemplate.opsForZSet().removeRange(key, start, end);
    }

    /**
     * 移除有序集 key 中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。
     * @param key key
     * @param min 小
     * @param max 大
     * @return 返回被移除成员的数量。
     */
    @Override
    public Long ZSetRemoveRangeByScore(String key, double min, double max) {
        return this.redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
    }

    /**
     * 计算给定的一个或多个有序集的并集，其中给定 key 的数量必须以 numkeys 参数指定，并将该并集(结果集)储存到 destination 。
     * @param key key
     * @param otherKey 其他key
     * @param destKey 目标key
     * @return 返回 保存到 destination 的结果集的基数。
     */
    @Override
    public Long ZSetUnionAndStore(String key, String otherKey, String destKey) {
        return this.redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * 计算给定的一个或多个有序集的并集，其中给定 key 的数量必须以 numkeys 参数指定，并将该并集(结果集)储存到 destination 。
     * @param key key
     * @param otherKey 其他key
     * @param destKey 目标key
     * @return 返回 保存到 destination 的结果集的基数。
     */
    @Override
    public Long ZSetUnionAndStore(String key, List<String> otherKey, String destKey) {
        return this.redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * 计算给定的一个或多个有序集的交集，其中给定 key 的数量必须以 numkeys 参数指定，并将该交集(结果集)储存到 destination 。
     * @param key key
     * @param otherKey 其他key
     * @param destKey  目标key
     * @return 返回保存到 destination 的结果集的基数。
     */
    @Override
    public Long ZSetIntersectAndStore(String key, String otherKey, String destKey) {
        return this.redisTemplate.opsForZSet().intersectAndStore(key, otherKey, destKey);
    }

    /**
     * 计算给定的一个或多个有序集的交集，其中给定 key 的数量必须以 numkeys 参数指定，并将该交集(结果集)储存到 destination 。
     * @param key key
     * @param otherKey 其他key
     * @param destKey  目标key
     * @return 返回保存到 destination 的结果集的基数。
     */
    @Override
    public Long ZSetIntersectAndStore(String key, List<String> otherKey, String destKey) {
        return this.redisTemplate.opsForZSet().intersectAndStore(key, otherKey, destKey);
    }

    /**
     * 命令用于迭代有序集合中的元素（包括元素成员和元素分值）
     * @param key key
     * @return Cursor
     */
    @Override
    public Cursor<ZSetOperations.TypedTuple<Object>> ZSetscan(String key) {
        return this.redisTemplate.opsForZSet().scan(key, ScanOptions.NONE);
    }

    /**
     * 令用于迭代有序集合中的元素（包括元素成员和元素分值）
     * @param key key
     * @return map
     */
    @Override
    public Map<Object, Object> ZSetScan(String key) {
        Cursor<ZSetOperations.TypedTuple<Object>> cursor = this.redisTemplate.opsForZSet().scan(key, ScanOptions.NONE);
        HashMap<Object, Object> map = new HashMap<>();

        while(cursor.hasNext()) {
            ZSetOperations.TypedTuple<Object> item = (ZSetOperations.TypedTuple<Object>)cursor.next();
            map.put(item.getValue(), item.getScore());
        }

        return map;
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
     * @param seconds 过期时间
     * @return boolean
     */
    @Override
    public boolean setSorted(String key, Object member, double score, long seconds) {
        boolean result = this.redisTemplate.opsForZSet().add(key, member, score);
        this.expire(key, seconds);
        return result;
    }

    /**
     * 为有序集 key 的成员 member 的 score 值加上增量 increment 。
     * @param seconds 带过期时间
     * @return double
     */
    @Override
    public double setSortedIncrement(String key, Object member, double score, long seconds) {
        double currentScore = this.redisTemplate.opsForZSet().incrementScore(key, member, score);
        this.expire(key, seconds);
        return currentScore;
    }

    /**
     * 返回有序集 key 中，成员 member 的 score 值。
     * @param key key
     * @param member 对象
     * @return 分值
     */
    @Override
    public double sortedScore(String key, Object member) {
        return this.redisTemplate.opsForZSet().score(key, member);
    }

    /**
     * 移除有序集 key 中的一个或多个成员，不存在的成员将被忽略。
     * @param key key
     * @param member 对成员象
     * @return boolean
     */
    @Override
    public boolean removeSorted(String key, Object member) {
        this.redisTemplate.opsForZSet().remove(key, new Object[]{member});
        return false;
    }

    /**
     * 返回有序集 key 中，指定区间内的成员。 带分页
     * @param key key
     * @param pageIndex 第几页
     * @param pageSize 一页大小
     * @param order 排序
     * @return 数据
     */
    @Override
    public Set<Object> rangeSorted(String key, int pageIndex, int pageSize, RedisSort order) {
        int start = (pageIndex - 1) * pageSize;
        int end = start + pageSize;
        return order == RedisSort.ASC ? this.redisTemplate.opsForZSet().range(key, (long)start, (long)end) : this.redisTemplate.opsForZSet().reverseRange(key, (long)start, (long)end);
    }

    /**
     * 返回有序集 key 中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
     * @param key key
     * @param minScore 最小分值
     * @param maxScore 最大分值
     * @param pageIndex 第几页
     * @param pageSize 一页的数量
     * @param order 排序
     * @return set
     */
    @Override
    public Set<Object> rangeSortedByScore(String key, double minScore, double maxScore, int pageIndex, int pageSize, RedisSort order) {
        int start = (pageIndex - 1) * pageSize;
        return order == RedisSort.ASC ? this.redisTemplate.opsForZSet().rangeByScore(key, minScore, maxScore, (long)start, (long)pageSize) : this.redisTemplate.opsForZSet().reverseRangeByScore(key, minScore, maxScore, (long)start, (long)pageSize);
    }

    /**
     * 返回有序集 key 中， score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。
     * @param key key
     * @param minScore 最小分数
     * @param maxScore 最大分数
     * @return Long
     */
    @Override
    public Long sortedCount(String key, double minScore, double maxScore) {
        return this.redisTemplate.opsForZSet().count(key, minScore, maxScore);
    }

    /**
     * 返回有序集 key 的基数。
     * @param key key
     * @return 数量
     */
    @Override
    public Long sortedSize(String key) {
        return this.redisTemplate.opsForZSet().size(key);
    }

    /**
     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
     * @param key key
     * @param member 成员
     * @param order 排序
     * @return 数量
     */
    @Override
    public Long sortedRank(String key, Object member, RedisSort order) {
        return order == RedisSort.ASC ? this.redisTemplate.opsForZSet().rank(key, member) : this.redisTemplate.opsForZSet().reverseRank(key, member);
    }

    /**
     * redis执行代码块 - RedisCallback
     * @param action 动作
     * @param <T> 泛型
     * @return RedisCallback
     */
    @Override
    public <T> T execute(RedisCallback<T> action) {
        return redisTemplate.execute(action);
    }

    /**
     * 因为pipeline减少了网络请求，减少了系统调用，所以会大幅提高系统性能
     * 使用pipeline组装的命令个数不能太多，不然数据量过大，增加客户端的等待时间，
     * 还可能造成网络阻塞，可以将大量命令的拆分多个小的pipeline命令完成
     * @param action 动作
     * @return list
     */
    @Override
    public List<Object> executePipelined(RedisCallback<?> action) {
        return redisTemplate.executePipelined(action);
    }

    /**
     *redis执行代码块 - SessionCallback
     * api比redisCallback 友好，优先使用。
     * @param session 会话
     * @param <T> session
     * @return 泛型
     */
    @Override
    public <T> T execute(SessionCallback<T> session) {
        return redisTemplate.execute(session);
    }

    /**
     *  Redis 管道 (Pipeline) 本身并不是 Redis 服务器直接提供的技术，
     * 这个技术本质上是由客户端提供的，
     * 跟服务器没有什么直接的关系。
     * @param session sessionCallback
     * @return list
     */
    @Override
    public List<Object> executePipelined(SessionCallback<?> session) {
        return redisTemplate.executePipelined(session);
    }

    /**
     * redis 4.0 之后的大key删除
     * @param key key
     * @return boolean
     */
    @Override
    public Boolean unlink(String key) {
        return redisTemplate.unlink(key);
    }

    /**
     * redis 4.0 之后的大key删除
     * @param keys list
     * @return 成功个数
     */
    @Override
    public Long unlink(List<String> keys) {
        return redisTemplate.unlink(keys);
    }

    public String getClusterName() {
        return clusterName;
    }

    public void setClusterName(String clusterName) {
        this.clusterName = clusterName;
    }
}
